package com.xbongbong.paas.service.stage.execute;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.xbongbong.i18n.util.I18nMessageUtil;
import com.xbongbong.paas.constant.MessageConstant;
import com.xbongbong.paas.constant.PaasConstant;
import com.xbongbong.paas.domain.entity.PaasFormDataEntity;
import com.xbongbong.paas.domain.entity.PaasFormExplainEntity;
import com.xbongbong.paas.domain.entity.PaasProcessDataEntity;
import com.xbongbong.paas.domain.entity.PaasStageEntity;
import com.xbongbong.paas.domain.entity.StageProcessEntity;
import com.xbongbong.paas.domain.entity.StageWorkLogEntity;
import com.xbongbong.paas.domain.entity.ext.PaasFormDataEntityExt;
import com.xbongbong.paas.domain.entity.ext.PaasFormEntityExt;
import com.xbongbong.paas.domain.entity.ext.PaasProcessTemplateEntityExt;
import com.xbongbong.paas.enums.DelEnum;
import com.xbongbong.paas.enums.FieldTypeEnum;
import com.xbongbong.paas.enums.StageTypeEnum;
import com.xbongbong.paas.field.FieldAttrEntity;
import com.xbongbong.paas.help.BusinessUserTeamHelp;
import com.xbongbong.paas.help.CommonHelp;
import com.xbongbong.paas.help.PaasFormHelp;
import com.xbongbong.paas.help.ProSaveHelp;
import com.xbongbong.paas.help.ProUpdateHelp;
import com.xbongbong.paas.help.StageDetailHelp;
import com.xbongbong.paas.help.WorkflowTransferHelp;
import com.xbongbong.paas.log.MongoLogHelp;
import com.xbongbong.paas.log.constant.CrmLogMemoConstant;
import com.xbongbong.paas.model.PaasFormExplainModel;
import com.xbongbong.paas.model.PaasFormModel;
import com.xbongbong.paas.model.PaasProcessDataModel;
import com.xbongbong.paas.model.PaasProcessTemplateModel;
import com.xbongbong.paas.pojo.dto.ParseSingleRowDataDTO;
import com.xbongbong.paas.pojo.dto.StartProcessDTO;
import com.xbongbong.paas.pojo.dto.UserAndDepartmentGetDTO;
import com.xbongbong.paas.pojo.dto.ValidateDataDTO;
import com.xbongbong.paas.pojo.vo.ParseSingleRowDataVO;
import com.xbongbong.paas.pojo.vo.StartProcessVO;
import com.xbongbong.paas.service.ProModelService;
import com.xbongbong.paas.service.dynamic.crm.strategy.DynamicStrategyFactory;
import com.xbongbong.paas.service.dynamic.crm.strategy.MainBusinessDynamicStrategy;
import com.xbongbong.paas.service.stage.StageJumpHandle;
import com.xbongbong.paas.service.workflow.trigger.WorkflowFormDataOperationService;
import com.xbongbong.paas.toolbox.exception.XbbException;
import com.xbongbong.paas.toolbox.util.BeanUtil;
import com.xbongbong.paas.toolbox.util.CloneUtil;
import com.xbongbong.paas.toolbox.util.CollectionsUtil;
import com.xbongbong.paas.toolbox.util.DateTimeUtil;
import com.xbongbong.paas.toolbox.util.JsonHelperUtil;
import com.xbongbong.paas.toolbox.util.StringUtil;
import com.xbongbong.paas.util.ExplainUtil;
import com.xbongbong.paas.util.FormDataUtil;
import com.xbongbong.parent.parse.data.FormDataListAnalysisDataHelp;
import com.xbongbong.pro.businessrule.pojo.BusinessRuleInfoPojo;
import com.xbongbong.pro.businesstage.pojo.LogInfoDealPojo;
import com.xbongbong.pro.businesstage.pojo.RequiredFieldPojo;
import com.xbongbong.pro.businesstage.pojo.dto.CommonJumpDTO;
import com.xbongbong.pro.businesstage.pojo.dto.StageFinishWorkDTO;
import com.xbongbong.pro.businesstage.pojo.dto.StageGetDTO;
import com.xbongbong.pro.businesstage.pojo.dto.StageJumpDealDTO;
import com.xbongbong.pro.businesstage.pojo.dto.StageJumpSpecialDealDTO;
import com.xbongbong.pro.businesstage.pojo.dto.StageJumpValidateDTO;
import com.xbongbong.pro.businesstage.pojo.vo.StageFinishWorkVO;
import com.xbongbong.pro.businesstage.pojo.vo.StageGetVO;
import com.xbongbong.pro.constant.I18nStringConstant;
import com.xbongbong.pro.constant.SymbolConstant;
import com.xbongbong.pro.customercommunicate.pojo.dto.CustomerDynamicAddDTO;
import com.xbongbong.pro.domain.entity.UpdateDataEntity;
import com.xbongbong.pro.dynamic.pojo.dto.DynamicStageJumpDTO;
import com.xbongbong.pro.enums.DistributorMarkEnum;
import com.xbongbong.pro.enums.PaasStageEnum;
import com.xbongbong.pro.enums.SaasMarkEnum;
import com.xbongbong.pro.enums.errorcodes.BomErrorCodeEnum;
import com.xbongbong.pro.enums.errorcodes.CustomerStageErrorCodeEnum;
import com.xbongbong.pro.enums.errorcodes.OpportunityErrorCodeEnum;
import com.xbongbong.pro.enums.errorcodes.SystemErrorCodeEnum;
import com.xbongbong.pro.enums.workflow.TriggerEventTypeEnum;
import com.xbongbong.pro.formexplain.pojo.dto.HandlerExplainDTO;
import com.xbongbong.pro.log.pojo.DetailLogPojo;
import com.xbongbong.pro.message.constant.OpportunityPushConstant;
import com.xbongbong.pro.message.enums.PushTypeEnum;
import com.xbongbong.pro.message.help.PushHelper;
import com.xbongbong.pro.message.pojo.PushRefTypePojo;
import com.xbongbong.pro.message.pojo.dto.MessageRabbitMqDTO;
import com.xbongbong.pro.rabbitmq.producer.BaseProducer;
import com.xbongbong.pro.thread.ThreadPoolBeanConfig;
import com.xbongbong.pro.weblist.pojo.dto.SaasBaseDTO;
import com.xbongbong.pro.workflow.enums.WorkflowExecutionTypeEnum;
import com.xbongbong.pro.workflow.enums.WorkflowOperateEnum;
import com.xbongbong.process.operate.ProcessStartHelp;
import com.xbongbong.saas.constant.BasicConstant;
import com.xbongbong.saas.constant.StringConstant;
import com.xbongbong.saas.domain.entity.OpportunityProductEntity;
import com.xbongbong.saas.domain.entity.OpportunityStageLogEntity;
import com.xbongbong.saas.domain.entity.OpportunityUserEntity;
import com.xbongbong.saas.domain.entity.OpportunityWorkLogEntity;
import com.xbongbong.saas.domain.entity.SaleStageEntity;
import com.xbongbong.saas.domain.entity.StaticForUpdateDTO;
import com.xbongbong.saas.domain.entity.UserTeamEntity;
import com.xbongbong.saas.domain.entity.ext.OpportunityEntityExt;
import com.xbongbong.saas.enums.OperateModuleTypeEnum;
import com.xbongbong.saas.enums.OperateTypeEnum;
import com.xbongbong.saas.enums.ProjectLogEnum;
import com.xbongbong.saas.enums.RedundantTemplateTypeEnum;
import com.xbongbong.saas.enums.UserTeamEnum;
import com.xbongbong.saas.enums.XbbRefTypeEnum;
import com.xbongbong.saas.enums.business.CustomerManagementEnum;
import com.xbongbong.saas.enums.business.SalesOpportunityEnum;
import com.xbongbong.saas.enums.dictionary.CustomerTypeEnum;
import com.xbongbong.saas.enums.dictionary.DictionaryEnum;
import com.xbongbong.saas.enums.dictionary.OpportunityLossCauseEnum;
import com.xbongbong.saas.help.CompetitorHelp;
import com.xbongbong.saas.help.OpportunityStageLogHelp;
import com.xbongbong.saas.help.SaveFormatHelp;
import com.xbongbong.saas.help.workflow.MarketActivityForStaticHelp;
import com.xbongbong.saas.model.CustomerModel;
import com.xbongbong.saas.model.OpportunityModel;
import com.xbongbong.saas.model.OpportunityProductModel;
import com.xbongbong.saas.model.OpportunityStageLogModel;
import com.xbongbong.saas.model.OpportunityUserModel;
import com.xbongbong.saas.model.OpportunityWorkLogModel;
import com.xbongbong.saas.model.SaleStageModel;
import com.xbongbong.saas.service.CustomerCommunicateService;
import com.xbongbong.saas.service.DictionaryService;
import com.xbongbong.saas.service.UserTeamService;
import com.xbongbong.saas.service.toolbox.help.LogHelp;
import com.xbongbong.saas.toolbox.help.FastJsonHelper;
import com.xbongbong.sys.domain.entity.DepartmentEntity;
import com.xbongbong.sys.domain.entity.UserEntity;
import com.xbongbong.workflow.domain.entity.WorkflowBackupDataEntity;
import com.xbongbong.workflow.domain.entity.WorkflowEntity;
import com.xbongbong.workflow.domain.entity.WorkflowExecutionEntity;
import com.xbongbong.workflow.domain.entity.WorkflowNodeEntity;
import com.xbongbong.workflow.domain.entity.WorkflowTaskEntity;
import com.xbongbong.workflow.domain.entity.WorkflowTransferDataEntity;
import com.xbongbong.workflow.model.WorkflowBackupDataModel;
import com.xbongbong.workflow.model.WorkflowNodeModel;
import com.xbongbong.workflow.model.WorkflowTaskModel;
import com.xbongbong.workflow.model.WorkflowTransferDataModel;
import com.xbongbong.workflow.pojo.Data;
import com.xbongbong.workflow.pojo.WorkflowRabbitmqDTO;
import com.xbongbong.workflow.pojo.WorkflowTransferPOJO;
import com.xbongbong.workflow.pojo.nodes.FormTriggerNode;
import com.xbongbong.workflow.producer.WorkflowProducer;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.elasticsearch.action.support.WriteRequest;
import org.springframework.beans.BeanUtils;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @author 吴峰
 * @date 2021/11/22 19:26
 */
@Slf4j
@Service("opportunityStageExecuteHandleImpl")
public class OpportunityStageExecuteHandleImpl extends AbstractStageExecuteHandle {

    @Resource
    private OpportunityStageLogModel opportunityStageLogModel;
    @Resource
    private SaleStageModel saleStageModel;
    @Resource
    private OpportunityModel opportunityModel;
    @Resource
    private OpportunityWorkLogModel opportunityWorkLogModel;
    @Resource
    private UserTeamService userTeamService;
    @Resource
    private PaasFormExplainModel paasFormExplainModel;
    @Resource
    private CommonHelp commonHelp;
    @Resource
    private ProModelService proModelService;
    @Resource
    private ThreadPoolBeanConfig threadPoolBeanConfig;
    @Resource
    private PushHelper pushHelper;
    @Resource
    @Lazy
    private CustomerCommunicateService customerCommunicateService;
    @Resource
    private BaseProducer baseProducer;
    @Resource
    private DictionaryService dictionaryService;
    @Resource
    private PaasProcessTemplateModel paasProcessTemplateModel;
    @Resource
    private WorkflowFormDataOperationService workflowFormDataOperationService;
    @Resource
    private WorkflowNodeModel workflowNodeModel;
    @Resource
    private OpportunityProductModel opportunityProductModel;
    @Resource
    private WorkflowBackupDataModel workflowBackupDataModel;
    @Resource
    private WorkflowProducer workflowProducer;
    @Resource
    private ProcessStartHelp processStartHelp;
    @Resource
    private OpportunityUserModel opportunityUserModel;
    @Resource
    private CustomerModel customerModel;
    @Resource
    private PaasFormModel paasFormModel;
    @Resource
    private MongoLogHelp mongoLogHelp;
    @Resource
    private PaasProcessDataModel paasProcessDataModel;
    @Resource
    private WorkflowTransferDataModel workflowTransferDataModel;
    @Resource
    private ProUpdateHelp proUpdateHelp;
    @Resource
    private StageDetailHelp stageDetailHelp;
    @Resource
    private Map<Integer, StageJumpHandle> stageJumpMap;
    @Resource
    private PaasFormHelp paasFormHelp;
    @Resource
    private BusinessUserTeamHelp businessUserTeamHelp;
    @Resource
    private FormDataListAnalysisDataHelp  formDataListAnalysisDataHelp;
    @Resource
    private WorkflowTaskModel workflowTaskModel;
    @Resource
    private DynamicStrategyFactory dynamicStrategyFactory;
    @Resource
    private MarketActivityForStaticHelp marketActivityForStaticHelp;
    @Resource
    private OpportunityStageLogHelp opportunityStageLogHelp;
    @Resource
    private LogHelp logHelp;

    @Override
    public Integer type() {
        return XbbRefTypeEnum.SALES_OPPORTUNITY.getCode();
    }

    @Override
    public void validate(StageJumpValidateDTO stageJumpValidateDTO) throws XbbException {
        String corpid = stageJumpValidateDTO.getCorpid();
        Long dataId = stageJumpValidateDTO.getDataId();
        PaasStageEntity toStageEntity = stageJumpValidateDTO.getToStageEntity();
        List<RequiredFieldPojo> requiredField = stageJumpValidateDTO.getRequiredField();
        OpportunityEntityExt opportunityEntityExt = opportunityModel.getByKey(dataId, corpid);
        PaasFormExplainEntity explain = paasFormExplainModel.getByFormId(opportunityEntityExt.getFormId(), opportunityEntityExt.getCorpid());
        if (Objects.isNull(explain)) {
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, MessageConstant.FORM_EXPLAIN_NOT_EXIST);
        }
        Map<String, FieldAttrEntity> explainMap = ExplainUtil.getExplainMap(explain.getExplains(), null);
        //机会转跳到输单校验必填
        if (Objects.nonNull(toStageEntity)) {
            // 机会转跳到输单时还需要判断设置中有没有勾选需要填写输单原因
            boolean causerCheck = false;
            if (Objects.nonNull(toStageEntity.getExtraSetting())) {
                Integer writeLossReason = toStageEntity.getExtraSetting().getInteger("writeLossReason");
                if (Objects.equals(writeLossReason, 1)) {
                    causerCheck = true;
                }
            }
            boolean isLose = Objects.equals(StageTypeEnum.FAIL_STAGE.getType(), toStageEntity.getType());
            if (isLose && causerCheck) {
                FieldAttrEntity fieldAttrEntity = explainMap.getOrDefault(SalesOpportunityEnum.WASTAGE.getAttr(), new FieldAttrEntity());
                boolean wastage = Objects.equals(fieldAttrEntity.getRequired(), 1) && Objects.equals(fieldAttrEntity.getIsOpen(), 1) && Objects.equals(fieldAttrEntity.getVisible(), 1);
                if (wastage && (Objects.isNull(stageJumpValidateDTO.getReasonId()) || stageJumpValidateDTO.getReasonId() <= 0)) {
                    throw new XbbException(OpportunityErrorCodeEnum.API_ERROR_202006);
                }
                FieldAttrEntity memoField = explainMap.getOrDefault(SalesOpportunityEnum.WASTAGE_MEMO.getAttr(), new FieldAttrEntity());
                boolean memoRequired = Objects.equals(memoField.getRequired(), 1) && Objects.equals(memoField.getIsOpen(), 1) && Objects.equals(memoField.getVisible(), 1);
                if (memoRequired && StringUtil.isEmpty(stageJumpValidateDTO.getMemo())) {
                    throw new XbbException(BomErrorCodeEnum.API_ERROR_242019);
                }
                // 判断每一个必填字段是否有值
                if (CollectionsUtil.isNotEmpty(requiredField)) {
                    for (RequiredFieldPojo temp : requiredField) {
                        if (Objects.isNull(temp.getValue())) {
                            throw new XbbException(CustomerStageErrorCodeEnum.API_ERROR_238049);
                        }
                    }
                }
            }
        }
    }

    @Override
    public StageGetVO get(StageGetDTO stageGetDTO) throws XbbException {
        StageGetVO stageGetVO = new StageGetVO();
        stageGetVO.setStageShowType(0);
        String corpid = stageGetDTO.getCorpid();
        Long formId = stageGetDTO.getFormId();
        Long dataId = stageGetDTO.getDataId();
        Integer saasMark = stageGetDTO.getSaasMark();
        //老审批流转状态
        Integer approveFlowStatus = null;
        //工作流审批流转状态
        Integer workflowFlowStatus = null;

        OpportunityEntityExt opportunityEntityExt = new OpportunityEntityExt();
        if (Objects.equals(stageGetDTO.getApproveType(), BasicConstant.ONE)) {
            PaasProcessDataEntity processDataEntity = paasProcessDataModel.getByTaskId(stageGetDTO.getProcessTaskId(), corpid);
            approveFlowStatus = processDataEntity.getFlowStatus();
            opportunityEntityExt.setData(JSONObject.parseObject(processDataEntity.getData()));
        } else if (Objects.equals(stageGetDTO.getApproveType(), BasicConstant.TWO)) {
            WorkflowTransferDataEntity workflowTransferDataEntity = workflowTransferDataModel.getByTaskId(stageGetDTO.getProcessTaskId(), corpid);
            JSONObject workFlowData = workflowTransferDataEntity.getData();
            JSONObject dataJSONObject = workFlowData.getJSONObject("data");
            opportunityEntityExt.setData(dataJSONObject.getJSONObject("data"));
            WorkflowTaskEntity workflowTaskEntity = workflowTaskModel.getByKey(stageGetDTO.getProcessTaskId(), corpid);
            workflowFlowStatus = Objects.isNull(workflowTaskEntity) ? null : workflowTaskEntity.getFlowStatus();
        } else {
            opportunityEntityExt = opportunityModel.getByKey(dataId, corpid);
            // 移动端透传关联数据时入参取不到最新formid
            formId = opportunityEntityExt.getFormId();
        }
        PaasFormExplainEntity explain = paasFormExplainModel.getByFormId(formId, corpid);
        if (Objects.isNull(explain)) {
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, MessageConstant.FORM_EXPLAIN_NOT_EXIST);
        }
        Map<String, FieldAttrEntity> explainMap = ExplainUtil.getExplainMap(explain.getExplains(), null);
        boolean checkshow = checkshow(stageGetDTO, opportunityEntityExt);
        if (!checkshow) {
            return stageGetVO;
        }
        Map<String, Object> params = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        Long stageProcessId = opportunityEntityExt.getData().getLong(SalesOpportunityEnum.STAGE_PROCESS_ID.getAttr());
        StageProcessEntity stageProcessEntity = getStageProcessEntity(stageGetDTO, stageProcessId, null, explainMap, opportunityEntityExt);
        if (Objects.isNull(stageProcessEntity)) {
            return stageGetVO;
        }
        stageProcessId = stageProcessEntity.getId();

        List<OpportunityStageLogEntity> opportunityStageLogEntities = new ArrayList<>();
        if (Objects.nonNull(dataId) && !Objects.equals(dataId, BasicConstant.ZERO_LONG)) {
            params.put("corpid", corpid);
            params.put("dataId", dataId);
            params.put("formId", formId);
            params.put("del", 0);
            opportunityStageLogEntities = opportunityStageLogModel.findEntitys(params);
        }

        params.clear();
        params.put("corpid", corpid);
        params.put("formId", formId);
        params.put("stageProcessId", stageProcessId);
        params.put("del", 0);
        params.put("orderByStr", "sort desc,add_time asc");
        List<SaleStageEntity> saleStageEntities = saleStageModel.findEntitys(params);
        Integer stageRation = opportunityEntityExt.getData().getInteger(SalesOpportunityEnum.STAGE_RATIO.getAttr());
        // 主逻辑
        stageGetVO = stageGet(stageRation, opportunityEntityExt, stageProcessEntity, stageGetDTO, opportunityStageLogEntities, saleStageEntities,approveFlowStatus, workflowFlowStatus);
        stageGetVO.setStageProcessId(stageProcessId);
        List<FieldAttrEntity> explainList = new ArrayList<>();
        explainList.add(explainMap.get(SalesOpportunityEnum.WASTAGE.getAttr()));
        explainList.add(explainMap.get(SalesOpportunityEnum.WASTAGE_MEMO.getAttr()));
        stageGetVO.setExplainList(explainList);
        return stageGetVO;
    }

    @Override
    public StageFinishWorkVO finishWork(StageFinishWorkDTO stageFinishWorkDTO) throws XbbException {
        return stageFinishWork(stageFinishWorkDTO);
    }

    @Override
    public void stageWorkLogSave(StageWorkLogEntity stageWorkLogEntity) throws XbbException {
        OpportunityWorkLogEntity opportunityWorkLogEntity = new OpportunityWorkLogEntity();
        BeanUtils.copyProperties(stageWorkLogEntity, opportunityWorkLogEntity);
        opportunityWorkLogModel.save(opportunityWorkLogEntity);
    }

    @Override
    public List<StageWorkLogEntity> stageWorkLogFindEntitys(Map<String, Object> params) {
        List<OpportunityWorkLogEntity> entitys = opportunityWorkLogModel.findEntitys(params);
        return Arrays.asList(entitys.toArray(new StageWorkLogEntity[0]));
    }

    @Override
    public boolean checkshow(StageGetDTO stageGetDTO, PaasFormDataEntityExt paasFormDataEntityExt) throws XbbException {
        String corpid = stageGetDTO.getCorpid();
        Long dataId = stageGetDTO.getDataId();
        if (Objects.equals(stageGetDTO.getApproveType(), BasicConstant.ONE) || Objects.equals(stageGetDTO.getApproveType(), BasicConstant.TWO)) {
            return true;
        }
        if (Objects.isNull(paasFormDataEntityExt)) {
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, MessageConstant.FORM_DATA_NOT_EXIST);
        }
        Long formId = paasFormDataEntityExt.getFormId();
        PaasFormExplainEntity explain = paasFormExplainModel.getByFormId(formId, corpid);
        if (Objects.isNull(explain)) {
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, MessageConstant.FORM_EXPLAIN_NOT_EXIST);
        }
        Map<String, FieldAttrEntity> explainMap = ExplainUtil.getExplainMap(explain.getExplains(), null);
        FieldAttrEntity stageEntity = explainMap.get(SalesOpportunityEnum.SALE_STAGE.getAttr());
        //协同团队
        Map<Long, List<String>> mainUserMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        Map<Long, List<String>> coUserMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        userTeamService.getUserIdMap(Collections.singletonList(paasFormDataEntityExt.getId()), corpid, XbbRefTypeEnum.SALES_OPPORTUNITY.getCode(), false, mainUserMap, coUserMap);
        // 当前数据的创建人、负责人、协同人、当前操作人
        HandlerExplainDTO handlerExplainDTO = new HandlerExplainDTO();
        BeanUtil.copyProperties(stageGetDTO, handlerExplainDTO);
        handlerExplainDTO.setOwnerId(mainUserMap.getOrDefault(paasFormDataEntityExt.getId(), new ArrayList<>()));
        handlerExplainDTO.setCoUserId(coUserMap.getOrDefault(paasFormDataEntityExt.getId(), new ArrayList<>()));
        handlerExplainDTO.setCreatorId(paasFormDataEntityExt.getCreatorId());
        if (!CommonHelp.ifStageOpen(XbbRefTypeEnum.SALES_OPPORTUNITY.getCode(), explainMap, handlerExplainDTO)) {
            return false;
        }
        if (Objects.nonNull(stageEntity)) {
            Integer stageProcessIdIsOpen = stageEntity.getIsOpen();
            Boolean fieldNeedHide = ExplainUtil.isFieldNeedHide(stageEntity, handlerExplainDTO);
            if (stageProcessIdIsOpen != 1 || fieldNeedHide) {
                return false;
            }
        }
        return true;
    }

    @Override
    public boolean checkFieldEditable(SaasBaseDTO saasBaseDTO) throws XbbException {
        String corpid = saasBaseDTO.getCorpid();
        Integer businessType = saasBaseDTO.getBusinessType();
        Integer saasMark = saasBaseDTO.getSaasMark();
        Long dataId = saasBaseDTO.getDataId();
        PaasFormDataEntityExt paasFormDataEntityExt = (PaasFormDataEntityExt) proModelService.getFormDataEntity(corpid, saasMark, businessType, dataId);
        if (Objects.isNull(paasFormDataEntityExt)) {
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, MessageConstant.FORM_DATA_NOT_EXIST);
        }
        Long formId = paasFormDataEntityExt.getFormId();
        PaasFormExplainEntity explain = paasFormExplainModel.getByFormId(formId, corpid);
        if (Objects.isNull(explain)) {
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, MessageConstant.FORM_EXPLAIN_NOT_EXIST);
        }
        Map<String, FieldAttrEntity> explainMap = ExplainUtil.getExplainMap(explain.getExplains(), null);
        //协同团队
        Map<Long, List<String>> mainUserMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        Map<Long, List<String>> coUserMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        userTeamService.getUserIdMap(Collections.singletonList(paasFormDataEntityExt.getId()), corpid, XbbRefTypeEnum.SALES_OPPORTUNITY.getCode(), false, mainUserMap, coUserMap);
        // 当前数据的创建人、负责人、协同人、当前操作人
        HandlerExplainDTO handlerExplainDTO = new HandlerExplainDTO();
        BeanUtil.copyProperties(saasBaseDTO, handlerExplainDTO);
        handlerExplainDTO.setOwnerId(mainUserMap.getOrDefault(paasFormDataEntityExt.getId(), new ArrayList<>()));
        handlerExplainDTO.setCoUserId(coUserMap.getOrDefault(paasFormDataEntityExt.getId(), new ArrayList<>()));
        handlerExplainDTO.setCreatorId(paasFormDataEntityExt.getCreatorId());
        return ExplainUtil.isStageEdit(SalesOpportunityEnum.SALE_STAGE.getAttr(), explainMap, handlerExplainDTO);
    }

    @Override
    public void afterJumpDeal(StageJumpDealDTO stageJumpDealDTO, PaasFormDataEntityExt paasFormDataEntityExt) throws XbbException {
        if (!Objects.equals(stageJumpDealDTO.getIsImport(), 1)) {
            Runnable stageRemindTask = () -> addStageTimeOutRemind(stageJumpDealDTO, paasFormDataEntityExt);
            threadPoolBeanConfig.stageRemindThreadPool().execute(stageRemindTask);
        }

        PaasStageEntity toStageEntity = stageJumpDealDTO.getToStageEntity();
        Boolean isNew = stageJumpDealDTO.getIsNew();
        if (Objects.nonNull(isNew) && isNew) {
            return;
        }
        if (Objects.isNull(toStageEntity)) {
            toStageEntity = new PaasStageEntity();
            toStageEntity.setName("开始阶段");
            toStageEntity.setType(StageTypeEnum.START_STAGE.getType());
            toStageEntity.setBusinessRelatedStatus(-1);
        }
        PaasStageEntity fromStageEntity = stageJumpDealDTO.getFromStageEntity();
        String nowStageName = fromStageEntity == null ? "开始阶段" : fromStageEntity.getName();
        String opportunityName = paasFormDataEntityExt.getSerialNo();
        String stageName = toStageEntity.getName();
        Integer stageType = toStageEntity.getType();
        String corpid = stageJumpDealDTO.getCorpid();
        Long opportunityId = paasFormDataEntityExt.getDataId();
        Long formId = stageJumpDealDTO.getFormId();
        String userId = stageJumpDealDTO.getUserId();
        String stageAttrName = stageJumpDealDTO.getStageAttrName();
        Integer reasonId = stageJumpDealDTO.getReasonId();
        Runnable runnable = () -> {
            try {
                // 生成项目日志
                List<DetailLogPojo> detailArr = new ArrayList();
                String oldTitle = nowStageName;
                String newTitle = stageName;
                String newMsg = String.format(SymbolConstant.BRACKETS_SQUARE_SOLID, newTitle);
                String oldMsg = String.format(SymbolConstant.BRACKETS_SQUARE_SOLID, oldTitle);
                detailArr.add(new DetailLogPojo(stageAttrName, stageAttrName, oldMsg, newMsg));
                PaasFormEntityExt paasFormEntityExt = paasFormModel.getByKey(formId, corpid);
                String logName = FastJsonHelper.getStringOrDefaultFromFormData(paasFormDataEntityExt.getData(), SalesOpportunityEnum.NAME.getAttr(), "");
                String memo = String.format(I18nMessageUtil.getMessage(I18nStringConstant.STAGE_OPERATION_LOG), stageJumpDealDTO.getLoginUserName(),
                        paasFormEntityExt.getName(), logName);
                String opObjectName = logName;
                mongoLogHelp.buildLog4DetailArr(detailArr, corpid, stageJumpDealDTO.getUserId(), stageJumpDealDTO.getLoginUserName(),
                        OperateModuleTypeEnum.OPPORTUNITY, OperateTypeEnum.EDIT, formId.toString(), opObjectName, memo, stageJumpDealDTO.getHttpHeader());
                String communicateMemo;
                if (Objects.equals(stageType, StageTypeEnum.FAIL_STAGE.getType())) {
                    //流失
                    Map<String, String> wastageReasonMap = dictionaryService.getDictionaryMap(DictionaryEnum.SALE_STAGE_WASTAGE, corpid, formId);
                    communicateMemo = String.format(I18nMessageUtil.getMessage(CrmLogMemoConstant.DYNAMIC_USER_SALES_STAGE_CHANGES_LOSE_REASON), stageJumpDealDTO.getLoginUserName(),
                            paasFormEntityExt.getName(), nowStageName, stageName, wastageReasonMap.get(stageJumpDealDTO.getReasonId().toString()), stageJumpDealDTO.getMemo());

                } else {
                    communicateMemo = String.format(I18nMessageUtil.getMessage(CrmLogMemoConstant.DYNAMIC_USER_STAGE), stageJumpDealDTO.getLoginUserName(), paasFormEntityExt.getName(), nowStageName, stageName);
                }

                if (Objects.equals(stageJumpDealDTO.getDistributorMark(), DistributorMarkEnum.DISTRIBUTOR.getCode())) {
                    // 项目日志
                     String customerName = paasFormDataEntityExt.getData().getString(SalesOpportunityEnum.CUSTOMER_NAME_LINK_TEXT.getAttr());
                     CustomerDynamicAddDTO customerDynamicAddDTO = new CustomerDynamicAddDTO();
                     customerDynamicAddDTO.setCorpid(corpid);
                     customerDynamicAddDTO.setUserId(userId);
                     customerDynamicAddDTO.setCustomerId(StringUtil.StringToLong(paasFormDataEntityExt.getData().getString(SalesOpportunityEnum.CUSTOMER_NAME.getAttr())));
                     customerDynamicAddDTO.setCustomerName(customerName);
                     customerDynamicAddDTO.setMemo(communicateMemo);
                     customerDynamicAddDTO.setCommunicateBusinessText(opportunityName);
                     customerDynamicAddDTO.setCommunicateBusinessType(XbbRefTypeEnum.SALES_OPPORTUNITY.getCode());
                     customerDynamicAddDTO.setDataId(opportunityId);
                     customerDynamicAddDTO.setLogType(ProjectLogEnum.OPPORTUNITY_STAGE.getSubType());
                     customerDynamicAddDTO.setDistributorMark(stageJumpDealDTO.getDistributorMark());
                     customerCommunicateService.addCustomerDynamic(customerDynamicAddDTO);
                } else {
                    MainBusinessDynamicStrategy dynamicStrategy = dynamicStrategyFactory.getMainBusinessDynamicStrategy(ProjectLogEnum.OPPORTUNITY_STAGE.getSubType());
                    dynamicStrategy.stageJump(DynamicStageJumpDTO.initDynamicStageJumpDTO(stageJumpDealDTO, paasFormDataEntityExt, communicateMemo));

                    // 机会输单原为竟品赢单时，该赢单竟品下需要添加动态
                    if (Objects.equals(OpportunityLossCauseEnum.COMPETITOR_WIN.getCode(),reasonId.toString())){
                        MainBusinessDynamicStrategy competitorDynamicStrategy = dynamicStrategyFactory.getMainBusinessDynamicStrategyByBusinessType(XbbRefTypeEnum.COMPETITOR.getCode());
                        competitorDynamicStrategy.stageJump(DynamicStageJumpDTO.initDynamicStageJumpDTO(stageJumpDealDTO,paasFormDataEntityExt,""));
                    }
                }

                // 机会阶段变更消息推送
                List<String> pushUserList = pushHelper.getUserIdListByPushSetRule(corpid, PushTypeEnum.OPPORTUNITY_CHANGE_PUSH.getCode(), PushTypeEnum.OPPORTUNITY_CHANGE_PUSH.getSubCode(), stageJumpDealDTO.getLoginUser(), paasFormDataEntityExt);
                if(CollectionsUtil.isNotEmpty(pushUserList)){
                    PushRefTypePojo.Options options = new PushRefTypePojo.Options(paasFormDataEntityExt.getAppId(), paasFormDataEntityExt.getMenuId(), paasFormDataEntityExt.getFormId(), opportunityId, Collections.singletonList(opportunityId), SaasMarkEnum.SAAS.getCode(), XbbRefTypeEnum.SALES_OPPORTUNITY.getCode(), XbbRefTypeEnum.SALES_OPPORTUNITY.getCode());
                    MessageRabbitMqDTO messageRabbitMqDTO = new MessageRabbitMqDTO(stageJumpDealDTO.getCorpid(), pushUserList, Collections.singletonList(opportunityId), 0, null, I18nMessageUtil.getMessage(OpportunityPushConstant.OPPORTUNITY_CHANGE_TITLE), String.format(I18nMessageUtil.getMessage(OpportunityPushConstant.OPPORTUNITY_CHANGE_CONTENT), stageJumpDealDTO.getLoginUserName(), opportunityName, stageName), null, options);
                    baseProducer.sendMessage(PushTypeEnum.OPPORTUNITY_CHANGE_PUSH, messageRabbitMqDTO);
                }
            } catch (Exception e) {
                log.error("机会阶段变更消息推送", e);
            }
        };
        threadPoolBeanConfig.addUpdateDelThreadPool().execute(runnable);
    }

    @Override
    public Integer approvalRequired(CommonJumpDTO commonJumpDTO, PaasFormDataEntityExt paasFormDataEntityExt, String stageAttr) throws XbbException {
        Integer noApprovalRequired = 1;
        String corpid = commonJumpDTO.getCorpid();
        Long formId = commonJumpDTO.getFormId();
        Long opportunityId = paasFormDataEntityExt.getDataId();
        PaasStageEntity toStageEntity = commonJumpDTO.getToStageEntity();
        Integer reasonId = commonJumpDTO.getReasonId();
        String memo = commonJumpDTO.getMemo();
        String nextStageCode = "";
        Long nextStageId = 0L;
        Long nextStageProcessId = 0L;
        Boolean isArchive = commonJumpDTO.getIsArchive();
        if (Objects.nonNull(toStageEntity)) {
            nextStageCode = toStageEntity.getCode();
            nextStageId = toStageEntity.getId();
            nextStageProcessId = toStageEntity.getStageProcessId();
        }
        if (commonHelp.isOpenWorkFlow(corpid)) {
            // 新工作流
            List<WorkflowEntity> workflowEntities = workflowFormDataOperationService.getSatisfyTriggerEntitys(corpid, formId, XbbRefTypeEnum.SALES_OPPORTUNITY.getCode(), Arrays.asList(TriggerEventTypeEnum.ONLY_UPDATE.getType(), TriggerEventTypeEnum.ADD_OR_UPDATE.getType()));
            for (WorkflowEntity workflowEntity : workflowEntities) {
                WorkflowNodeEntity startNode = workflowNodeModel.getByUId(workflowEntity.getId(), corpid, "startNode");
                FormTriggerNode formTriggerNode = JSON.parseObject(startNode.getConfigData(), FormTriggerNode.class);
                if (CollectionsUtil.isEmpty(formTriggerNode.getNeedApproveFields()) || formTriggerNode.getNeedApproveFields().contains(SalesOpportunityEnum.SALE_STAGE.getAttr())) {
                    //是否启用新工作流
                    PaasFormExplainEntity explain = paasFormExplainModel.getByFormId(formId, corpid);
                    Map<String, FieldAttrEntity> explainMap = ExplainUtil.getExplainMap(explain.getExplains(), null);
                    BusinessRuleInfoPojo businessRuleInfoPojo = new BusinessRuleInfoPojo(startNode.getCorpid(), startNode.getFormId(), startNode.getBusinessType(), startNode.getSaasMark(),explainMap);
                    PaasFormDataEntityExt paasFormDataEntityExtClone = (PaasFormDataEntityExt) CloneUtil.deepClone(paasFormDataEntityExt);
                    if (Objects.nonNull(toStageEntity)) {
                        // 详情页阶段跳转，用跳转之后的阶段去匹配触发条件-----59089 【KA大客户】【B级】阶段审批异常
                        paasFormDataEntityExtClone.getData().put(stageAttr, toStageEntity.getCode());
                    }
                    boolean flag = workflowFormDataOperationService.validatePreCondition(formTriggerNode.getTriggerConditions(), paasFormDataEntityExtClone, businessRuleInfoPojo);
                    if(!flag){
                        break;
                    }

                    workflowRequired(paasFormDataEntityExt, startNode, commonJumpDTO, WorkflowExecutionTypeEnum.FORM, stageAttr, null);
                    if (Objects.equals(1, workflowEntity.getIsApprove())) {
                        noApprovalRequired = 3;
                    } else {
                        // 无审批节点
                        noApprovalRequired = 4;
                    }
                    break;
                }
            }
        } else {
            // 审批
            Map<String, Object> params = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            params.put("del", 0);
            params.put("corpid", corpid);
            params.put("formId", formId);
            params.put("businessType", XbbRefTypeEnum.SALES_OPPORTUNITY.getCode());
            params.put("enable", 1);
            List<PaasProcessTemplateEntityExt> paasProcessTemplateEntityExtList = paasProcessTemplateModel.list(params);
            if (paasProcessTemplateEntityExtList.size() > 0 && paasProcessTemplateEntityExtList.get(0).getNeedApproveFieldList().contains(SalesOpportunityEnum.SALE_STAGE.getAttr())) {
                JSONObject newData = (JSONObject) CloneUtil.deepClone(paasFormDataEntityExt.getData());
                newData.remove(SalesOpportunityEnum.PRODUCTS.getAttr());
                newData.put(SalesOpportunityEnum.SALE_STAGE.getAttr(), nextStageCode);
                newData.put(PaasStageEnum.STAGE_PROCESS_ID.getAttr(), nextStageProcessId);
                newData.put(PaasStageEnum.STAGE_ID.getAttr(), nextStageId);

                //计算阶段比例
                StageJumpHandle stageJumpHandle = stageJumpMap.get(toStageEntity.getType());
                Integer proportion = stageJumpHandle.getJumpIntoProportion(paasFormDataEntityExt.getId(), corpid, formId, toStageEntity.getId(), SaasMarkEnum.SAAS.getCode(), XbbRefTypeEnum.SALES_OPPORTUNITY.getCode(), toStageEntity.getOutProportion());

                //处理输单机会输单原因需要更新的数据
                JSONObject loseOrderRelationData =  getLoseOrderRelationData(toStageEntity.getExtraSetting(), isArchive, commonJumpDTO.getMemo(), commonJumpDTO.getReasonId(), commonJumpDTO.getRequiredField(), 0);
                if (!loseOrderRelationData.isEmpty()) {
                    analyseLoseOrderRelationData(formId, corpid, loseOrderRelationData);
                }
                newData.put(PaasStageEnum.STAGE_RATIO.getAttr(), proportion);
                if (!loseOrderRelationData.isEmpty()) {
                    newData.putAll(loseOrderRelationData);
                }
                Map<Integer, List<UserTeamEntity>> userMap = userTeamService.getUserTeam(paasFormDataEntityExt.getId(), corpid, XbbRefTypeEnum.SALES_OPPORTUNITY.getCode());
                // 负责人
                if (userMap.containsKey(1)) {
                    List<UserTeamEntity> mainUserList = userMap.get(1);
                    List<String> mainIdList = new ArrayList<>();
                    for (UserTeamEntity userTeamEntity : mainUserList) {
                        mainIdList.add(userTeamEntity.getUserId());
                    }
                    newData.put(SalesOpportunityEnum.OWNER_ID.getAttr(), mainIdList);
                }
                if (userMap.containsKey(0)) {
                    List<UserTeamEntity> coUserList = userMap.get(0);
                    List<String> coIdList = new ArrayList<>();
                    for (UserTeamEntity userTeamEntity : coUserList) {
                        coIdList.add(userTeamEntity.getUserId());
                    }
                    newData.put(SalesOpportunityEnum.COUSER_ID.getAttr(), coIdList);
                }
                List<OpportunityProductEntity> productList = opportunityProductModel.getProductsByOppId(paasFormDataEntityExt.getId(), corpid);
                opportunityStageLogHelp.formatProductForProcess(productList, newData);
                StartProcessDTO startProcessDTO = new StartProcessDTO();
                BeanUtil.copyProperties(commonJumpDTO, startProcessDTO);
                BeanUtil.copyProperties(paasFormDataEntityExt, startProcessDTO);
                startProcessDTO.setData(newData);
                startProcessDTO.setFormDataId(paasFormDataEntityExt.getId());
                startProcessDTO.setCreatorId(commonJumpDTO.getUserId());
                startProcessDTO.setSaasMark(1);
                startProcessDTO.setBusinessType(XbbRefTypeEnum.SALES_OPPORTUNITY.getCode());
                StartProcessVO startProcessVO = processStartHelp.startProcess(startProcessDTO, paasFormDataEntityExt);
                noApprovalRequired = startProcessVO.getNoApprovalRequired();
            }
        }
        return noApprovalRequired;
    }

    @Override
    public void workflowRequired(PaasFormDataEntityExt paasFormDataEntityExt, WorkflowNodeEntity startNode, CommonJumpDTO commonJumpDTO, WorkflowExecutionTypeEnum workflowExecutionTypeEnum, String stageAttr, WorkflowExecutionEntity workflowExecutionEntity) throws XbbException {
        String corpid = commonJumpDTO.getCorpid();
        Long formId = commonJumpDTO.getFormId();
        Long opportunityId = paasFormDataEntityExt.getDataId();
        PaasStageEntity toStageEntity = commonJumpDTO.getToStageEntity();
        Integer reasonId = commonJumpDTO.getReasonId();
        String memo = commonJumpDTO.getMemo();
        String nextStageCode = "";
        Long nextStageId = 0L;
        Long nextStageProcessId = 0L;
        Integer proportion = 0;
        Boolean isArchive = commonJumpDTO.getIsArchive();
        JSONObject loseOrderRelationData = new JSONObject();
        if (Objects.nonNull(toStageEntity)) {
            nextStageCode = toStageEntity.getCode();
            nextStageId = toStageEntity.getId();
            nextStageProcessId = toStageEntity.getStageProcessId();
            //计算阶段比例
            StageJumpHandle stageJumpHandle = stageJumpMap.get(toStageEntity.getType());
            proportion = stageJumpHandle.getJumpIntoProportion(paasFormDataEntityExt.getId(), corpid, formId, toStageEntity.getId(), SaasMarkEnum.SAAS.getCode(), XbbRefTypeEnum.SALES_OPPORTUNITY.getCode(), toStageEntity.getOutProportion());

            //处理输单机会输单原因需要更新的数据
            loseOrderRelationData =  getLoseOrderRelationData(toStageEntity.getExtraSetting(), isArchive, commonJumpDTO.getMemo(), commonJumpDTO.getReasonId(), commonJumpDTO.getRequiredField(), 0);
            if (!loseOrderRelationData.isEmpty()) {
                analyseLoseOrderRelationData(formId, corpid, loseOrderRelationData);
            }
        }

        // backup
        JSONObject oldDataObj = (JSONObject) CloneUtil.deepClone(paasFormDataEntityExt.getData());
        FormDataUtil.setSystemData(oldDataObj, paasFormDataEntityExt);
        long now = DateTimeUtil.getInt();
        List<OpportunityUserEntity> contactList = opportunityUserModel.getOpportunityUserList(corpid, opportunityId, null);
        oldDataObj.put(StringConstant.USER_TEAM, contactList);
        List<OpportunityProductEntity> productList = opportunityProductModel.getProductsByOppId(opportunityId, corpid);
        oldDataObj.put(StringConstant.PRODUCT, productList);
        WorkflowBackupDataEntity workflowBackupDataEntity = new WorkflowBackupDataEntity(corpid, paasFormDataEntityExt.getAppId(),
                paasFormDataEntityExt.getFormId(), paasFormDataEntityExt.getMenuId(), 0L, 0L, opportunityId, oldDataObj, now, now, DelEnum.NORMAL.getDel());
        workflowBackupDataModel.insert(workflowBackupDataEntity);

        //构建mq消息
        FormDataUtil.setSystemData(paasFormDataEntityExt.getData(), paasFormDataEntityExt);
        Data oldData = new Data(startNode.getAppId(), startNode.getMenuId(), startNode.getFormId(), paasFormDataEntityExt.getId(),
                oldDataObj, startNode.getBusinessType(), startNode.getSaasMark(), startNode.getId(), XbbRefTypeEnum.SALES_OPPORTUNITY.getCode());
        // 将需要更新的字段，更新到主数据
        JSONObject updateDataJson = new JSONObject();
        updateDataJson.put(SalesOpportunityEnum.SALE_STAGE.getAttr(), nextStageCode);
        List<OpportunityProductEntity> productEntities = opportunityProductModel.getProductsByOppId(paasFormDataEntityExt.getId(), corpid);
        opportunityStageLogHelp.formatProductForProcess(productEntities, paasFormDataEntityExt.getData());
        if (Objects.nonNull(toStageEntity) && Objects.equals(toStageEntity.getType(), StageTypeEnum.FAIL_STAGE.getType())) {
            if(Objects.nonNull(commonJumpDTO.getReasonId())){
                updateDataJson.put(SalesOpportunityEnum.WASTAGE.getAttr(), commonJumpDTO.getReasonId().toString());
            }
            updateDataJson.put(SalesOpportunityEnum.WASTAGE_MEMO.getAttr(), commonJumpDTO.getMemo());
        } else {
            updateDataJson.put(SalesOpportunityEnum.WASTAGE.getAttr(), "");
            updateDataJson.put(SalesOpportunityEnum.WASTAGE_MEMO.getAttr(), "");
        }
        // 存放阶段流程id
        updateDataJson.put(PaasStageEnum.STAGE_PROCESS_ID.getAttr(), nextStageProcessId);
        // 存放阶段id
        updateDataJson.put(PaasStageEnum.STAGE_ID.getAttr(), nextStageId);

        updateDataJson.put(PaasStageEnum.STAGE_RATIO.getAttr(), proportion);
        //存放输单原因的相关数据
        if (!loseOrderRelationData.isEmpty()) {
            updateDataJson.putAll(loseOrderRelationData);
        }
        // 更新数据
        UpdateDataEntity updateData = ExplainUtil.getUpdateData(opportunityId, updateDataJson, corpid);
        opportunityModel.updateBatch(Collections.singletonList(updateData), corpid, WriteRequest.RefreshPolicy.NONE);

        WorkflowTransferPOJO workflowTransferPOJO = WorkflowTransferHelp.createTransferData(paasFormDataEntityExt, null, null, null, corpid,
                commonJumpDTO.getLoginUser(), startNode, WorkflowOperateEnum.UPDATE.getType(), 0, XbbRefTypeEnum.SALES_OPPORTUNITY.getCode());
        workflowTransferPOJO.setBackupDataId(workflowBackupDataEntity.getId());
        workflowTransferPOJO.setOldData(oldData);

        workflowTransferPOJO.setExecutionType(workflowExecutionTypeEnum.getCode());
        workflowTransferPOJO.setIsFromStage(true);
        workflowTransferPOJO.setToStageId(nextStageId);
        if (Objects.isNull(commonJumpDTO.getFromStageEntity())) {
            workflowTransferPOJO.setFromStageId(null);
        } else {
            workflowTransferPOJO.setFromStageId(commonJumpDTO.getFromStageEntity().getId());
        }
        if (!Objects.isNull(workflowExecutionEntity)) {
            workflowTransferPOJO.setParentExecutionId(workflowExecutionEntity.getId());
            workflowTransferPOJO.setLinkKey(workflowExecutionEntity.getLinkKey());
        }
        workflowTransferPOJO.setStageProcessId(commonJumpDTO.getStageProcessEntity().getId());

        JSONObject newDataObj = new JSONObject();
        newDataObj.putAll(oldDataObj);
        newDataObj.putAll(updateDataJson);
        Data newData = new Data(startNode.getAppId(), startNode.getMenuId(), startNode.getFormId(), paasFormDataEntityExt.getId(),
                newDataObj, startNode.getBusinessType(), startNode.getSaasMark(), startNode.getId(), XbbRefTypeEnum.SALES_OPPORTUNITY.getCode());
        workflowTransferPOJO.setData(newData);

        WorkflowRabbitmqDTO workflowRabbitmqDTO = new WorkflowRabbitmqDTO(workflowTransferPOJO, startNode, null);
        workflowProducer.startWorkflow(workflowRabbitmqDTO);
    }

    /**
     * 解析输单原因需要更新的数据
     * @param formId
     * @param corpid
     */
    private void analyseLoseOrderRelationData(Long formId, String corpid, JSONObject loseOrderRelationData) throws XbbException {
        PaasFormExplainEntity formExplainEntity = paasFormExplainModel.getByFormId(formId, corpid);
        String explains = formExplainEntity.getExplains();
        Map<String, FieldAttrEntity> explainMap = ExplainUtil.getExplainMap(explains, null);
        List<FieldAttrEntity> fieldAttrEntityList = explainMap.values().stream().filter(item -> loseOrderRelationData.containsKey(item.getAttr())).collect(Collectors.toList());
        explainMap = fieldAttrEntityList.stream().collect(Collectors.toMap(FieldAttrEntity::getAttr, Function.identity()));
        ValidateDataDTO validateDataDTO = new ValidateDataDTO();
        validateDataDTO.setData(loseOrderRelationData);
        validateDataDTO.setExplainMap(explainMap);
        // 通用数据格式转换
        ProSaveHelp.analyticalData(validateDataDTO);
        // 解析标签的格式
        SaveFormatHelp.dealLabelData(validateDataDTO.getData(), explainMap);
    }

    /**
     * 获取输单原因需要更新的数据
     * @param extraSetting
     * @param isArchive
     * @param memo
     * @param reasonId
     * @param requiredField
     * @return
     */
    private JSONObject getLoseOrderRelationData(JSONObject extraSetting, Boolean isArchive, String memo, Integer reasonId, List<RequiredFieldPojo> requiredField, Integer fromApproval) {
        JSONObject loseOrderRelationData = new JSONObject();
        Integer writeLossReason = 0;
        if (Objects.nonNull(extraSetting)) {
            writeLossReason= extraSetting.getInteger("writeLossReason");
        }
        if (Objects.nonNull(isArchive) && isArchive) {
            loseOrderRelationData.put(SalesOpportunityEnum.IS_ARCHIVED.getAttr(), 1);
        }
        // 没有开启审批才需要将输单原因跟备注，特殊字段更新
        if (Objects.equals(writeLossReason, 1) && !Objects.equals(1, fromApproval)) {
            loseOrderRelationData.put(SalesOpportunityEnum.WASTAGE_MEMO.getAttr(), memo);
            loseOrderRelationData.put(SalesOpportunityEnum.WASTAGE.getAttr(), reasonId);
            if (CollectionsUtil.isNotEmpty(requiredField)) {
                requiredField.forEach(e -> {
                    loseOrderRelationData.put(e.getAttr(), e.getValue());
                });
            }
        }
        if(loseOrderRelationData.containsKey(SalesOpportunityEnum.WIN_COMPETITOR.getAttr())){
            loseOrderRelationData.put(SalesOpportunityEnum.WIN_COMPETITOR_LINK_TEXT.getAttr(),"");
        }
        return loseOrderRelationData;
    }

    @Override
    public void jumpSpecialDeal(StageJumpSpecialDealDTO stageJumpSpecialDealDTO) throws XbbException {
        String corpid = stageJumpSpecialDealDTO.getCorpid();
        Long dataId = stageJumpSpecialDealDTO.getDataId();
        Boolean isArchive = stageJumpSpecialDealDTO.getIsArchive();
        String memo = stageJumpSpecialDealDTO.getMemo();
        Integer reasonId = stageJumpSpecialDealDTO.getReasonId();
        Boolean isUpdateStatus = stageJumpSpecialDealDTO.getIsUpdateStatus();
        Integer toStageType = stageJumpSpecialDealDTO.getToStageType();
        String nextStageCode = stageJumpSpecialDealDTO.getToStageEntity().getCode();
        Long toStageId = stageJumpSpecialDealDTO.getToStageEntity().getId();
        Integer saasMark = stageJumpSpecialDealDTO.getSaasMark();
        Integer businessType = stageJumpSpecialDealDTO.getBusinessType();
        Long formId = stageJumpSpecialDealDTO.getFormId();
        Integer fromApproval = stageJumpSpecialDealDTO.getFromApproval();

        try {
            OpportunityEntityExt opportunityEntityExt = opportunityModel.getByKey(dataId, corpid);
            List<StaticForUpdateDTO> list = new ArrayList<>();
            StaticForUpdateDTO staticForUpdateDTO = new StaticForUpdateDTO();
            staticForUpdateDTO.setId(dataId);
            JSONObject jsonObject = new JSONObject();
            jsonObject.put(SalesOpportunityEnum.SALE_STAGE.getAttr(), nextStageCode);
            staticForUpdateDTO.setData(jsonObject);
            list.add(staticForUpdateDTO);
            //处理编辑接口(市场活动统计中间表)
            marketActivityForStaticHelp.updateBatchMarketActivity(list, XbbRefTypeEnum.SALES_OPPORTUNITY ,corpid);

            if (Objects.equals(toStageType, StageTypeEnum.SUCCESS_STAGE.getType())) {
                //机会转跳到赢单，是否更新关联客户状态
                if (Objects.nonNull(isUpdateStatus) && isUpdateStatus) {

                    String customerId = opportunityEntityExt.getData().getString(SalesOpportunityEnum.CUSTOMER_NAME.getAttr());
                    if (StringUtil.isNotEmpty(customerId)) {
                        Long id = Long.parseLong(customerId);
                        Map<String, Object> map = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                        map.put(CustomerManagementEnum.TYPE.getAttr(), CustomerTypeEnum.TRANSACTION_CUSTOMER.getCode());
                        customerModel.jsonsetNoSubById(corpid, id, map);
                    }
                }
            } else if (Objects.equals(toStageType, StageTypeEnum.FAIL_STAGE.getType())) {
                // 转跳到失败阶段，机会的跳转特殊逻辑：判断是否归档，更新主数据归档状态,填入输单原因与备注
                // 转跳到失败阶段，还需要将必填字段更新
                SaleStageEntity saleStageEntity = saleStageModel.getByKey(toStageId, corpid);
                JSONObject map = getLoseOrderRelationData(saleStageEntity.getExtraSetting(), isArchive, memo, reasonId, stageJumpSpecialDealDTO.getRequiredField(), fromApproval);
                if (!map.isEmpty()){
                    PaasFormExplainEntity formExplainEntity = paasFormExplainModel.getByFormId(stageJumpSpecialDealDTO.getFormId(), stageJumpSpecialDealDTO.getCorpid());
                    String explains = formExplainEntity.getExplains();
                    Map<String, FieldAttrEntity> explainMap = ExplainUtil.getExplainMap(explains, null);
                    List<FieldAttrEntity> fieldAttrEntityList = explainMap.values().stream().filter(item -> map.containsKey(item.getAttr())).collect(Collectors.toList());
                    explainMap = fieldAttrEntityList.stream().collect(Collectors.toMap(FieldAttrEntity::getAttr, Function.identity()));
                    ValidateDataDTO validateDataDTO = new ValidateDataDTO();
                    validateDataDTO.setData(map);
                    validateDataDTO.setExplainMap(explainMap);
                    // 通用数据格式转换
                    ProSaveHelp.analyticalData(validateDataDTO);
                    // 解析标签的格式
                    SaveFormatHelp.dealLabelData(validateDataDTO.getData(), explainMap);
                    // 解析竞争对手
                    CompetitorHelp.formatWinCompetitorLinkBusiness4Save(validateDataDTO.getData());
                    List<UpdateDataEntity> updateDataEntityList = new ArrayList<>();
                    UpdateDataEntity updateData = ExplainUtil.getUpdateData(dataId, map, corpid);
                    updateDataEntityList.add(updateData);
                    proUpdateHelp.updateBatch(saasMark, businessType, corpid, updateDataEntityList);
                    // 没开审批才需要添加日志,开了审批
                    if (!Objects.equals(1, fromApproval)){
                        JSONObject newData = analyseData(stageJumpSpecialDealDTO, corpid, dataId, businessType, opportunityEntityExt, map, explainMap, fieldAttrEntityList);
                        JSONObject oldData = analyseData(stageJumpSpecialDealDTO, corpid, dataId, businessType, opportunityEntityExt, opportunityEntityExt.getData(), explainMap, fieldAttrEntityList);

                        PaasFormDataEntity newPaasFormDataEntity = new PaasFormDataEntity();
                        newPaasFormDataEntity.setData(newData);
                        PaasFormDataEntity oldPaasFormDataEntity = new PaasFormDataEntity();
                        oldPaasFormDataEntity.setData(oldData);
                        JSONObject newObj = JsonHelperUtil.parseObject(JSONObject.toJSONString(newPaasFormDataEntity));
                        JSONObject oldObj = JsonHelperUtil.parseObject(JSONObject.toJSONString(oldPaasFormDataEntity));
                        List<DetailLogPojo> detailArr = logHelp.getDetailArr4Data(corpid, RedundantTemplateTypeEnum.SALES_OPPORTUNITY, explainMap, oldObj, newObj);

//                        List<DetailLogPojo> detailArr = new ArrayList<>();
//                        for (String attr : newData.keySet()) {
//                            FieldAttrEntity fieldAttrEntity = explainMap.get(attr);
//                            if (Objects.isNull(fieldAttrEntity)) {
//                                continue;
//                            }
//                            Object value = newData.get(attr);
//                            Object oldValue = oldData.get(attr);
//                            detailArr.add(new DetailLogPojo(fieldAttrEntity.getAttrNameEn(), fieldAttrEntity.getAttrName(),
//                                    Objects.isNull(oldValue) ? "" : oldValue.toString(), Objects.isNull(value) ? "" : value.toString()));
//                        }
                        // 保存日志前需要将数据格式解析
                        Runnable runnable = () -> {
                            try {
                                LogInfoDealPojo logInfoDealPojo = stageDetailHelp.dealLogInfo(corpid, formId, saasMark, businessType, opportunityEntityExt);
                                String opObjectName = logInfoDealPojo.getOpObjectName();
                                OperateModuleTypeEnum operateModuleTypeEnum = OperateModuleTypeEnum.OPPORTUNITY;
                                PaasFormEntityExt paasFormEntityExt = paasFormModel.getByKey(formId, corpid);
                                // 53701 日志--跳转到输单阶段，关联竞争对手、赢单竞品，名字展示错误
                                addStageChangedDetailArr(stageJumpSpecialDealDTO,detailArr);
                                String memoLog = String.format(I18nMessageUtil.getMessage(I18nStringConstant.STAGE_OPERATION_LOG), stageJumpSpecialDealDTO.getLoginUserName(),
                                        paasFormEntityExt.getName(), opObjectName);
                                mongoLogHelp.buildLog4DetailArr(detailArr, corpid, stageJumpSpecialDealDTO.getUserId(), stageJumpSpecialDealDTO.getLoginUserName(),
                                        operateModuleTypeEnum, OperateTypeEnum.EDIT, formId.toString(), opObjectName, memoLog, stageJumpSpecialDealDTO.getHttpHeader());
                            } catch (Exception e) {
                                log.error("执行事件日志", e);
                            }
                        };
                        threadPoolBeanConfig.addUpdateDelThreadPool().execute(runnable);
                    }
                }
            } else if (Objects.equals(toStageType, StageTypeEnum.CANCEL_STAGE.getType())) {
                //机会转跳到取消，更改主数据是否归档
                if (Objects.nonNull(isArchive) && isArchive) {
                    Map<String, Object> map = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                    map.put(SalesOpportunityEnum.IS_ARCHIVED.getAttr(), 1);
                    opportunityModel.jsonsetNoSubById(corpid, dataId, map);
                }
            }
        } catch (Exception e) {
            log.error("转跳到失败阶段，机会更新归档出错", e);
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001);
        }
    }

    private JSONObject analyseData(StageJumpSpecialDealDTO stageJumpSpecialDealDTO, String corpid, Long dataId, Integer businessType, OpportunityEntityExt opportunityEntityExt, JSONObject dataJsonObject, Map<String, FieldAttrEntity> explainMap, List<FieldAttrEntity> fieldAttrEntityList) throws XbbException {
        try {
            //协同团队
            Map<Long, List<String>> mainUserMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            Map<Long, List<String>> coUserMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            Map<Long, List<String>> paasCoUserMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            Set userIdList = new HashSet();
            userIdList.add(stageJumpSpecialDealDTO.getUserId());
            ArrayList dataIdList = new ArrayList<>();
            dataIdList.add(dataId);
            if (UserTeamEnum.hasTeam(businessType)) {
                businessUserTeamHelp.getUserIdMapSetShow(userIdList, dataIdList, corpid, businessType, false, mainUserMap, coUserMap, DelEnum.NORMAL.getDel());
            } else {
                paasCoUserMap = businessUserTeamHelp.coUserMapShow(userIdList, dataIdList, corpid);
            }
            ParseSingleRowDataDTO parseSingleRowDataDTO = new ParseSingleRowDataDTO();
            BeanUtil.copyProperties(stageJumpSpecialDealDTO, parseSingleRowDataDTO);
            dataJsonObject.put(FieldTypeEnum.CREATORID.getAlias(), opportunityEntityExt.getCreatorId());
            // 设置创建人
            parseSingleRowDataDTO.setCreatorId(opportunityEntityExt.getCreatorId());
            formDataListAnalysisDataHelp.setOwnerIdAndCoUserId(businessType, dataJsonObject, parseSingleRowDataDTO, opportunityEntityExt, mainUserMap, coUserMap, paasCoUserMap);

            Map<String, UserEntity> userMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            HandlerExplainDTO handlerExplainDTO = new HandlerExplainDTO();
            BeanUtil.copyProperties(stageJumpSpecialDealDTO, handlerExplainDTO, false);
            handlerExplainDTO.setCreatorId(opportunityEntityExt.getCreatorId());
            handlerExplainDTO.setExplainList(fieldAttrEntityList);
            paasFormHelp.getOwnerIdAndCoUserId(handlerExplainDTO, stageJumpSpecialDealDTO.getSaasMark(), stageJumpSpecialDealDTO.getBusinessType(), stageJumpSpecialDealDTO.getSubBusinessType(), opportunityEntityExt, userMap);

            UserAndDepartmentGetDTO userAndDepartmentGetDTO = new UserAndDepartmentGetDTO();
            BeanUtil.copyProperties(stageJumpSpecialDealDTO, userAndDepartmentGetDTO);
            userAndDepartmentGetDTO.setExplainList(fieldAttrEntityList);
            Map<String, DepartmentEntity> departmentMap = commonHelp.getDepMap(userAndDepartmentGetDTO);

            parseSingleRowDataDTO.setDataJsonObject(dataJsonObject);
            parseSingleRowDataDTO.setUserMap(userMap);
            parseSingleRowDataDTO.setDepartmentMap(departmentMap);
            parseSingleRowDataDTO.setExplainMap(explainMap);
            parseSingleRowDataDTO.setListFlag(1);
            parseSingleRowDataDTO.setDataId(dataId);
            parseSingleRowDataDTO.setFormId(stageJumpSpecialDealDTO.getFormId());
            // 解析单行数据
            ParseSingleRowDataVO parseSingleRowDataVO = formDataListAnalysisDataHelp.parseSingleRowData(parseSingleRowDataDTO);
            if (Objects.nonNull(parseSingleRowDataVO) && Objects.nonNull(parseSingleRowDataVO.getResult()) && !parseSingleRowDataVO.getResult().isEmpty()) {
                return parseSingleRowDataVO.getResult();
            } else {
                return dataJsonObject;
            }
        } catch (XbbException e) {
            return dataJsonObject;
        }
    }

    private void addStageChangedDetailArr(StageJumpSpecialDealDTO stageJumpSpecialDealDTO,List<DetailLogPojo> detailArr){
        try {
            if (CollectionUtils.isEmpty(detailArr)){
                return;
            }
            String stageAttrName = stageJumpSpecialDealDTO.getStageAttrName();
            PaasStageEntity fromStageEntity = stageJumpSpecialDealDTO.getFromStageEntity();
            String from = fromStageEntity == null ? "" : fromStageEntity.getName();
            PaasStageEntity toStageEntity = stageJumpSpecialDealDTO.getToStageEntity();
            String to = toStageEntity == null ? "" : toStageEntity.getName();
            DetailLogPojo stageChanged = new DetailLogPojo(stageAttrName, stageAttrName, from, to);
            detailArr.add(0,stageChanged);
        } catch (Exception e) {
            log.error("OpportunityStageExecuteHandleImpl.addStageChangedDetailArr exception" + e);
        }
    }
}
